﻿using System;
using System.Collections.Generic;

namespace YawetagLib.Data
{
    public abstract class BaseDataContextFactory : IDataContextFactory
    {
        private readonly object _lock = new object();

        protected BaseDataContextFactory()
        {
            Initializers = new Dictionary<Type, Func<Guid, IDataContext>>();
            Instances = new Dictionary<DataContextToken, IDataContext>();
        }

        public void Register(DataContextInfo info)
        {
            SetDefaultType(info.Type);

            lock (_lock)
            {
                if (!Initializers.ContainsKey(info.Type))
                {
                    Initializers.Add(info.Type, info.Initializer);
                }
            }
        }

        private void SetDefaultType(Type type)
        {
            lock (_lock)
            {
                if (DefaultType == null)
                {
                    DefaultType = type;
                }
            }
        }

        public IDataContext Get(DataContextToken token)
        {
            lock (_lock)
            {
                if (!Instances.ContainsKey(token))
                {
                    Instances.Add(token, GetDataContextInstance(token));
                }
            }

            return Instances[token];
        }

        public IDataContext GetDefault(Guid identifier)
        {
            return Get(DataContextToken.New(DefaultType, identifier));
        }

        public IDataContext GetDefault()
        {
            return GetDefault(Guid.Empty);
        }

        protected virtual IDataContext GetDataContextInstance(DataContextToken token)
        {
            return Initializers[token.Type](token.Identifier);
        }

        public void Dispose()
        {
            foreach (IDataContext dataContext in Instances.Values)
            {
                dataContext.Dispose();
            }
        }

        protected Type DefaultType { get; set; }

        protected IDictionary<Type, Func<Guid, IDataContext>> Initializers { get; set; }
        protected IDictionary<DataContextToken, IDataContext> Instances { get; set; }
    }
}
